package com.trytech.mongoocrawler.common.transport.protocol;

import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @author jiangtao@meituan.com
 * @since: Created on 2018年03月28日
 */
public class ProtocolDecoder extends ByteToMessageDecoder implements Protocol {

    private boolean isContent = false;

    private CrawlerTransferProtocol protocol = new CrawlerTransferProtocol();

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        byte[] ibyte = new byte[4];
        byteBuf.getBytes(byteBuf.readerIndex(), ibyte);

        if (byteBuf.readableBytes() > 0 && (isContent || (!isContent && compareBytes(MAGIC, ibyte)))) {
            if (!isContent) {
                byteBuf.readBytes(ibyte);
                byte typeByte = byteBuf.readByte();
                protocol.setType(typeByte);

                int classNameLen = byteBuf.readInt();
                byte[] classNameByteArr = new byte[classNameLen];
                byteBuf = byteBuf.readBytes(classNameByteArr);
                String className = new String(classNameByteArr);
                protocol.setCls(Class.forName(className));
            }
            byteBuf.markReaderIndex();

            int contentLen = byteBuf.readInt();
            if (contentLen <= 0) {
                channelHandlerContext.close();
            } else {
                if (byteBuf.readableBytes() < contentLen) {
                    isContent = true;
                    byteBuf.resetReaderIndex();
                    return;
                }
                //读取正文
                byte[] content = new byte[contentLen];
                byteBuf = byteBuf.readBytes(content);
                String contentStr = new String(content, "UTF-8");
                protocol.setContent((AbstractProtocol) JSONObject.parseObject(contentStr, protocol.getCls()));

                if (protocol != null) {
                    list.add(protocol);
                }
                if (isContent) {
                    isContent = false;
                }
            }
        }
    }

    private boolean compareBytes(byte[] source, byte[] dst) {
        if (source == null || dst == null || source.length != dst.length) {
            return false;
        }
        for (int i = 0; i < source.length; i++) {
            if (source[i] != dst[i]) {
                return false;
            }
        }
        return true;
    }
}
